/*
Rilego - An easy Images 2 E-Book converter.
Copyright (C) 2011  Federico Improta (Kirys)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */
package it.kirys.rilego.gui;

import it.kirys.rilego.engine.Engine;
import it.kirys.rilego.engine.EngineStatusInfo;
import it.kirys.rilego.engine.ICallBack;
import it.kirys.rilego.engine.loaders.DiskFileLoader;
import it.kirys.rilego.engine.loaders.ZipPackageLoader;
import it.kirys.rilego.engine.loaders.imagesources.IImageSource;
import it.kirys.rilego.engine.loaders.imagesources.Orientation;
import it.kirys.rilego.engine.loaders.imagesources.SourceRotation;
import it.kirys.rilego.engine.outputbuilders.IMediaType;
import it.kirys.rilego.engine.outputbuilders.MediaType;
import it.kirys.rilego.engine.outputbuilders.OutputDirection;
import it.kirys.rilego.engine.outputbuilders.PdfBuilder;
import it.kirys.rilego.engine.processors.AbstractFullProcessor;
import it.kirys.rilego.engine.processors.IActiveProcessorFactory;
import it.kirys.rilego.engine.processors.BasicFullProcessorFactory;
import it.kirys.rilego.engine.processors.transformers.IImageSplitter;
import it.kirys.rilego.engine.processors.transformers.SplitToTwo;
import it.kirys.rilego.engine.project.Project;
import it.kirys.rilego.gui.customclasses.GuiOutputCompression;
import it.kirys.rilego.gui.customclasses.ImageComboBoxRenderer;
import it.kirys.rilego.gui.customclasses.SourcesTableModel;
import it.kirys.rilego.gui.customclasses.PDFFileFilter;
import it.kirys.rilego.gui.customclasses.SimpleImagePanel;
import it.kirys.rilego.gui.customclasses.SplitMode;
import it.kirys.rilego.gui.customclasses.SupportedImagesFileFilter;
import it.kirys.rilego.gui.customclasses.SupportedPackagesFileFilter;
import it.kirys.rilego.gui.filtersmanager.FiltersManager;
import it.kirys.rilego.gui.filtersmanager.FiltersTreeModel;
import it.kirys.rilego.gui.filtersmanager.nodesmanaging.LeafEditor;
import it.kirys.rilego.gui.filtersmanager.nodesmanaging.LeafRenderer;
import it.kirys.rilego.gui.filtersmanager.setters.IFilterSetter;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.LinkedList;
import javax.swing.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.DefaultComboBoxModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerListModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import org.jdesktop.application.Action;

/**
 * This class is the main frame of the Gui
 * @author Federico Improta
 */
public class MainFrame extends javax.swing.JFrame implements ICallBack {

	private static final Integer[] workesNumberList = new Integer[]{1, 2, 4, 6, 8};
	private int currentSelection = -1;
	private Timer monitor;
	private Icon idleIcon;
	private Icon[] busyAnimationIcons = new Icon[15];
	private int busyIconIndex = 0;
	Engine engine;
	Desktop desktop;
	private Project project;
	private FiltersManager manager;

	/** Creates new form MainFrame */
	public MainFrame() {
		initComponents();
		initStatusBar();
		initDesktop();
		newProject();
	}

	/**
	 * Open default browser to visit an url
	 * @param url url to open
	 */
	protected void browseUrl(String url) {
		if (url != null) {
			if (desktop.isSupported(Desktop.Action.BROWSE)) {
				URI uri = null;
				try {
					uri = new URI(url);
					desktop.browse(uri);
				} catch (Exception ex) {
					JOptionPane.showMessageDialog(null, "It was not possible to open default browser");
				}
			} else {
				JOptionPane.showMessageDialog(null, "It was not possible to open default browser");
			}
		} else {
			JOptionPane.showMessageDialog(null, "It was not possible to open default browser");
		}
	}//protected void browseUrl(String url)

	/**
	 * this method load an icon from the jar resources
	 * @param location location of the image icon into the resources
	 * @return the loaded icon image
	 * @throws IOException
	 */
	public static Icon loadIcon(String location) throws IOException {
		InputStream stream = MainFrame.class.getResourceAsStream(location);
		BufferedImage image = ImageIO.read(stream);
		Icon out = new ImageIcon(image);
		return out;
	}

	/**
	 * Init desktop related methods
	 */
	private void initDesktop() {
		if (Desktop.isDesktopSupported()) {
			desktop = Desktop.getDesktop();
		} else {
			desktop = null;
		}
	}//private void initDesktop()

	/**
	 * This method init the status bar and all the animation/icons of the "running status"
	 */
	private void initStatusBar() {
		int busyAnimationRate = 30;
		for (int i = 0; i < busyAnimationIcons.length; i++) {
			try {
				busyAnimationIcons[i] = loadIcon("/progressanimation/busy-icon" + i + ".png");
			} catch (IOException ex) {
				Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
		monitor = new Timer(busyAnimationRate, new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if (engine != null) {
					busyIconIndex = (busyIconIndex + 1) % busyAnimationIcons.length;
					iconContainer.setIcon(busyAnimationIcons[busyIconIndex]);
				}
			}
		});
		try {
			idleIcon = loadIcon("/progressanimation/idle-icon.png");
		} catch (IOException ex) {
			Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
		}

		progressBar.setVisible(false);
		iconContainer.setIcon(idleIcon);

	}

	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
   // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
   private void initComponents() {

      SourcesPopupMenu = new javax.swing.JPopupMenu();
      MultipleSelectionMenu = new javax.swing.JMenu();
      InvertSelectionMenuItem = new javax.swing.JMenuItem();
      SelectHorizontalMenuItem = new javax.swing.JMenuItem();
      SelectVerticalMenuItem = new javax.swing.JMenuItem();
      SelectAllMenuItem = new javax.swing.JMenuItem();
      TransformationSeparator = new javax.swing.JPopupMenu.Separator();
      MassSetMenuItem = new javax.swing.JMenuItem();
      ActionSeparator = new javax.swing.JPopupMenu.Separator();
      DeleteMenuItem = new javax.swing.JMenuItem();
      StatusPanel = new javax.swing.JPanel();
      progressBar = new javax.swing.JProgressBar();
      iconContainer = new javax.swing.JLabel();
      statusLabel = new javax.swing.JLabel();
      MainToolbar = new javax.swing.JToolBar();
      AddImagesButton = new javax.swing.JButton();
      AddDirectoryButton = new javax.swing.JButton();
      AddZipPackageButton = new javax.swing.JButton();
      jSeparator1 = new javax.swing.JToolBar.Separator();
      workersNumberLabel = new javax.swing.JLabel();
      workersSpinner = new javax.swing.JSpinner();
      MainTabbedPanel = new javax.swing.JTabbedPane();
      SourcesPanel = new javax.swing.JSplitPane();
      SourcesScrollPanel = new javax.swing.JScrollPane();
      SourcesTable = 		new javax.swing.JTable() {

         protected JTableHeader createDefaultTableHeader() {
            return new JTableHeader(columnModel) {

               public String getToolTipText(MouseEvent e) {
                  String tip = null;
                  java.awt.Point p = e.getPoint();
                  int index = columnModel.getColumnIndexAtX(p.x);
                  int realIndex = columnModel.getColumn(index).getModelIndex();
                  return SourcesTableModel.getColumnHint(realIndex);
               }
            };
         }

         public Component prepareRenderer(TableCellRenderer renderer,
            int rowIndex, int vColIndex) {
            TableModel tm = SourcesTable.getModel();
            Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
            if (tm instanceof SourcesTableModel) {
               SourcesTableModel stm=(SourcesTableModel) tm;
               if (c instanceof JComponent) {
                  JComponent jc = (JComponent) c;
                  String hint= stm.getCellHint(rowIndex, vColIndex);
                  if (hint!=null){
                     jc.setToolTipText(hint);
                  } else {
                     jc.setToolTipText("");
                  }
               }
            }
            return c;
         }
      };
      SourcesPreviewPanel = new SimpleImagePanel();
      ImagesProcessingOptionsPanel = new javax.swing.JSplitPane();
      FiltersPanel = new javax.swing.JPanel();
      SplitModePanel = new javax.swing.JPanel();
      splitModeCombo = new javax.swing.JComboBox();
      ImagesProcessingPanel = new javax.swing.JPanel();
      FiltersPropertiesTreeScroller = new javax.swing.JScrollPane();
      FiltersPropertiesTree = new javax.swing.JTree();
      outputPanel = new javax.swing.JPanel();
      DirectionLabel = new javax.swing.JLabel();
      OutputDirectionCombo = new javax.swing.JComboBox();
      titleLabel = new javax.swing.JLabel();
      titleTextField = new javax.swing.JTextField();
      authorLabel = new javax.swing.JLabel();
      authorTextField = new javax.swing.JTextField();
      mediaTypeLabel = new javax.swing.JLabel();
      mediaTypeCombo = new javax.swing.JComboBox();
      imageCompressionTypeLabel = new javax.swing.JLabel();
      ImageCompressionCombo = new javax.swing.JComboBox();
      jPanel1 = new javax.swing.JPanel();
      GenerateButton = new javax.swing.JButton();
      PreviewButton = new javax.swing.JButton();
      PreviewPanelScroller = new javax.swing.JScrollPane();
      FilterPreviewPanel = new SimpleImagePanel(false);
      InfoLogScroll = new javax.swing.JScrollPane();
      InfoLogArea = new javax.swing.JTextArea();
      MainMenu = new javax.swing.JMenuBar();
      projectMenu = new javax.swing.JMenu();
      addImagesMenuItem = new javax.swing.JMenuItem();
      addDirectoryMenuItem = new javax.swing.JMenuItem();
      jMenuItem3 = new javax.swing.JMenuItem();
      jSeparator2 = new javax.swing.JPopupMenu.Separator();
      jMenuItem4 = new javax.swing.JMenuItem();
      jSeparator3 = new javax.swing.JPopupMenu.Separator();
      exitMenuItem = new javax.swing.JMenuItem();
      HelpMenu = new javax.swing.JMenu();
      helpMenuItem = new javax.swing.JMenuItem();
      helpSeparator = new javax.swing.JPopupMenu.Separator();
      reportIssueItem = new javax.swing.JMenuItem();
      rilegoWebsiteItem = new javax.swing.JMenuItem();
      issueSeparator = new javax.swing.JPopupMenu.Separator();
      aboutMenuItem = new javax.swing.JMenuItem();

      MultipleSelectionMenu.setText("Select");

      InvertSelectionMenuItem.setText("Invert Selection");
      MultipleSelectionMenu.add(InvertSelectionMenuItem);

      SelectHorizontalMenuItem.setText("Select Horizontal Images");
      SelectHorizontalMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            SelectHorizontalMenuItemActionPerformed(evt);
         }
      });
      MultipleSelectionMenu.add(SelectHorizontalMenuItem);

      SelectVerticalMenuItem.setText("Select Vertical Images");
      SelectVerticalMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            SelectVerticalMenuItemActionPerformed(evt);
         }
      });
      MultipleSelectionMenu.add(SelectVerticalMenuItem);

      SelectAllMenuItem.setText("Select All");
      SelectAllMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            SelectAllMenuItemActionPerformed(evt);
         }
      });
      MultipleSelectionMenu.add(SelectAllMenuItem);

      SourcesPopupMenu.add(MultipleSelectionMenu);
      SourcesPopupMenu.add(TransformationSeparator);

      MassSetMenuItem.setText("Set options");
      MassSetMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            MassSetMenuItemActionPerformed(evt);
         }
      });
      SourcesPopupMenu.add(MassSetMenuItem);
      SourcesPopupMenu.add(ActionSeparator);

      DeleteMenuItem.setText("Delete");
      DeleteMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            DeleteMenuItemActionPerformed(evt);
         }
      });
      SourcesPopupMenu.add(DeleteMenuItem);

      setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
      setTitle(it.kirys.rilego.gui.GuiVersionInfo.APP_FULLNAME);
      setIconImage(new javax.swing.ImageIcon(getClass().getResource("/logo/Rilego32.png")).getImage());

      iconContainer.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
      iconContainer.setIcon(new javax.swing.ImageIcon(getClass().getResource("/progressanimation/idle-icon.png"))); // NOI18N
      iconContainer.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);

      statusLabel.setText("Idle");

      javax.swing.GroupLayout StatusPanelLayout = new javax.swing.GroupLayout(StatusPanel);
      StatusPanel.setLayout(StatusPanelLayout);
      StatusPanelLayout.setHorizontalGroup(
         StatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, StatusPanelLayout.createSequentialGroup()
            .addComponent(statusLabel)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 627, Short.MAX_VALUE)
            .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(iconContainer)
            .addGap(15, 15, 15))
      );
      StatusPanelLayout.setVerticalGroup(
         StatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addComponent(statusLabel)
         .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
         .addComponent(iconContainer)
      );

      MainToolbar.setRollover(true);

      javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance().getContext().getActionMap(MainFrame.class, this);
      AddImagesButton.setAction(actionMap.get("addImagesAction")); // NOI18N
      AddImagesButton.setFocusable(false);
      AddImagesButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
      AddImagesButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
      MainToolbar.add(AddImagesButton);

      AddDirectoryButton.setAction(actionMap.get("addDirectoryAction")); // NOI18N
      AddDirectoryButton.setFocusable(false);
      AddDirectoryButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
      AddDirectoryButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
      MainToolbar.add(AddDirectoryButton);

      AddZipPackageButton.setAction(actionMap.get("addZipPackageAction")); // NOI18N
      AddZipPackageButton.setFocusable(false);
      AddZipPackageButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
      AddZipPackageButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
      AddZipPackageButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            AddZipPackageButtonActionPerformed(evt);
         }
      });
      MainToolbar.add(AddZipPackageButton);
      MainToolbar.add(jSeparator1);

      workersNumberLabel.setText("Workers: ");
      MainToolbar.add(workersNumberLabel);

      workersSpinner.setModel(new SpinnerListModel(workesNumberList));
      workersSpinner.setMaximumSize(new java.awt.Dimension(40, 32767));
      MainToolbar.add(workersSpinner);

      SourcesTable.setModel(new javax.swing.table.DefaultTableModel(
         new Object [][] {
            {null, null, null, null},
            {null, null, null, null},
            {null, null, null, null},
            {null, null, null, null}
         },
         new String [] {
            "Title 1", "Title 2", "Title 3", "Title 4"
         }
      ));
      SourcesTable.setComponentPopupMenu(SourcesPopupMenu);
      SourcesTable.addMouseListener(new java.awt.event.MouseAdapter() {
         public void mouseReleased(java.awt.event.MouseEvent evt) {
            SourcesTableMouseReleased(evt);
         }
      });
      SourcesTable.addKeyListener(new java.awt.event.KeyAdapter() {
         public void keyReleased(java.awt.event.KeyEvent evt) {
            SourcesTableKeyReleased(evt);
         }
      });
      SourcesScrollPanel.setViewportView(SourcesTable);

      SourcesPanel.setLeftComponent(SourcesScrollPanel);

      javax.swing.GroupLayout SourcesPreviewPanelLayout = new javax.swing.GroupLayout(SourcesPreviewPanel);
      SourcesPreviewPanel.setLayout(SourcesPreviewPanelLayout);
      SourcesPreviewPanelLayout.setHorizontalGroup(
         SourcesPreviewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGap(0, 374, Short.MAX_VALUE)
      );
      SourcesPreviewPanelLayout.setVerticalGroup(
         SourcesPreviewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGap(0, 458, Short.MAX_VALUE)
      );

      SourcesPanel.setRightComponent(SourcesPreviewPanel);

      MainTabbedPanel.addTab("Sources", SourcesPanel);

      ImagesProcessingOptionsPanel.setDividerLocation(310);

      FiltersPanel.setMinimumSize(new java.awt.Dimension(300, 100));
      FiltersPanel.setPreferredSize(new java.awt.Dimension(300, 458));

      SplitModePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Split mode"));

      splitModeCombo.setModel(new DefaultComboBoxModel(SplitMode.values()));
      splitModeCombo.setPreferredSize(new java.awt.Dimension(40, 44));
      splitModeCombo.setRenderer(new ImageComboBoxRenderer());

      javax.swing.GroupLayout SplitModePanelLayout = new javax.swing.GroupLayout(SplitModePanel);
      SplitModePanel.setLayout(SplitModePanelLayout);
      SplitModePanelLayout.setHorizontalGroup(
         SplitModePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(SplitModePanelLayout.createSequentialGroup()
            .addContainerGap()
            .addComponent(splitModeCombo, 0, 263, Short.MAX_VALUE)
            .addContainerGap())
      );
      SplitModePanelLayout.setVerticalGroup(
         SplitModePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(SplitModePanelLayout.createSequentialGroup()
            .addComponent(splitModeCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
      );

      ImagesProcessingPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Filters"));

      FiltersPropertiesTree.setModel(new FiltersTreeModel(manager));
      FiltersPropertiesTree.setCellEditor(new LeafEditor(FiltersPropertiesTree));
      FiltersPropertiesTree.setCellRenderer(new LeafRenderer());
      FiltersPropertiesTree.setEditable(true);
      FiltersPropertiesTree.setRootVisible(false);
      FiltersPropertiesTree.setShowsRootHandles(true);
      FiltersPropertiesTreeScroller.setViewportView(FiltersPropertiesTree);

      javax.swing.GroupLayout ImagesProcessingPanelLayout = new javax.swing.GroupLayout(ImagesProcessingPanel);
      ImagesProcessingPanel.setLayout(ImagesProcessingPanelLayout);
      ImagesProcessingPanelLayout.setHorizontalGroup(
         ImagesProcessingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addComponent(FiltersPropertiesTreeScroller, javax.swing.GroupLayout.DEFAULT_SIZE, 287, Short.MAX_VALUE)
      );
      ImagesProcessingPanelLayout.setVerticalGroup(
         ImagesProcessingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addComponent(FiltersPropertiesTreeScroller, javax.swing.GroupLayout.DEFAULT_SIZE, 157, Short.MAX_VALUE)
      );

      outputPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Output"));
      outputPanel.setLayout(new java.awt.GridLayout(0, 2, 2, 0));

      DirectionLabel.setLabelFor(OutputDirectionCombo);
      DirectionLabel.setText("Direction");
      outputPanel.add(DirectionLabel);

      OutputDirectionCombo.setModel(new DefaultComboBoxModel(OutputDirection.values()));
      outputPanel.add(OutputDirectionCombo);

      titleLabel.setLabelFor(titleTextField);
      titleLabel.setText("Document Title");
      outputPanel.add(titleLabel);
      outputPanel.add(titleTextField);

      authorLabel.setLabelFor(authorTextField);
      authorLabel.setText("Document Author");
      outputPanel.add(authorLabel);
      outputPanel.add(authorTextField);

      mediaTypeLabel.setText("Media");
      outputPanel.add(mediaTypeLabel);

      mediaTypeCombo.setModel(new DefaultComboBoxModel(MediaType.values()));
      outputPanel.add(mediaTypeCombo);

      imageCompressionTypeLabel.setText("Compression");
      outputPanel.add(imageCompressionTypeLabel);

      ImageCompressionCombo.setModel(new DefaultComboBoxModel(GuiOutputCompression.values()));
      outputPanel.add(ImageCompressionCombo);

      GenerateButton.setText("Generate");
      GenerateButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            GenerateButtonActionPerformed(evt);
         }
      });

      PreviewButton.setText("Preview");
      PreviewButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            PreviewButtonActionPerformed(evt);
         }
      });

      javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
      jPanel1.setLayout(jPanel1Layout);
      jPanel1Layout.setHorizontalGroup(
         jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
            .addContainerGap(100, Short.MAX_VALUE)
            .addComponent(PreviewButton)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(GenerateButton))
      );
      jPanel1Layout.setVerticalGroup(
         jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
            .addComponent(GenerateButton, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addComponent(PreviewButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
      );

      javax.swing.GroupLayout FiltersPanelLayout = new javax.swing.GroupLayout(FiltersPanel);
      FiltersPanel.setLayout(FiltersPanelLayout);
      FiltersPanelLayout.setHorizontalGroup(
         FiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, FiltersPanelLayout.createSequentialGroup()
            .addGroup(FiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
               .addComponent(ImagesProcessingPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
               .addComponent(outputPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE)
               .addComponent(SplitModePanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
               .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            .addContainerGap())
      );
      FiltersPanelLayout.setVerticalGroup(
         FiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(FiltersPanelLayout.createSequentialGroup()
            .addComponent(SplitModePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(ImagesProcessingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(outputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
      );

      ImagesProcessingOptionsPanel.setLeftComponent(FiltersPanel);

      javax.swing.GroupLayout FilterPreviewPanelLayout = new javax.swing.GroupLayout(FilterPreviewPanel);
      FilterPreviewPanel.setLayout(FilterPreviewPanelLayout);
      FilterPreviewPanelLayout.setHorizontalGroup(
         FilterPreviewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGap(0, 540, Short.MAX_VALUE)
      );
      FilterPreviewPanelLayout.setVerticalGroup(
         FilterPreviewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGap(0, 455, Short.MAX_VALUE)
      );

      PreviewPanelScroller.setViewportView(FilterPreviewPanel);

      ImagesProcessingOptionsPanel.setRightComponent(PreviewPanelScroller);

      MainTabbedPanel.addTab("Images Processing", ImagesProcessingOptionsPanel);

      InfoLogArea.setColumns(20);
      InfoLogArea.setEditable(false);
      InfoLogArea.setRows(5);
      InfoLogScroll.setViewportView(InfoLogArea);

      MainTabbedPanel.addTab("InfoLog", InfoLogScroll);

      projectMenu.setMnemonic('P');
      projectMenu.setText("Project");

      addImagesMenuItem.setAction(actionMap.get("addImagesAction")); // NOI18N
      addImagesMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            addImagesMenuItemActionPerformed(evt);
         }
      });
      projectMenu.add(addImagesMenuItem);

      addDirectoryMenuItem.setAction(actionMap.get("addDirectoryAction")); // NOI18N
      projectMenu.add(addDirectoryMenuItem);

      jMenuItem3.setAction(actionMap.get("addZipPackageAction")); // NOI18N
      projectMenu.add(jMenuItem3);
      projectMenu.add(jSeparator2);

      jMenuItem4.setAction(actionMap.get("clearProject")); // NOI18N
      projectMenu.add(jMenuItem4);
      projectMenu.add(jSeparator3);

      exitMenuItem.setMnemonic('x');
      exitMenuItem.setText("Exit");
      exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            exitMenuItemActionPerformed(evt);
         }
      });
      projectMenu.add(exitMenuItem);

      MainMenu.add(projectMenu);

      HelpMenu.setMnemonic('h');
      HelpMenu.setText("Help");

      helpMenuItem.setText("Help");
      helpMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            helpMenuItemActionPerformed(evt);
         }
      });
      HelpMenu.add(helpMenuItem);
      HelpMenu.add(helpSeparator);

      reportIssueItem.setText("Report an issue");
      reportIssueItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            reportIssueItemActionPerformed(evt);
         }
      });
      HelpMenu.add(reportIssueItem);

      rilegoWebsiteItem.setText("Visit rilego website");
      rilegoWebsiteItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            rilegoWebsiteItemActionPerformed(evt);
         }
      });
      HelpMenu.add(rilegoWebsiteItem);
      HelpMenu.add(issueSeparator);

      aboutMenuItem.setText("About");
      aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            aboutMenuItemActionPerformed(evt);
         }
      });
      HelpMenu.add(aboutMenuItem);

      MainMenu.add(HelpMenu);

      setJMenuBar(MainMenu);

      javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
      getContentPane().setLayout(layout);
      layout.setHorizontalGroup(
         layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addComponent(MainToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, 844, Short.MAX_VALUE)
         .addComponent(StatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
         .addComponent(MainTabbedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 844, Short.MAX_VALUE)
      );
      layout.setVerticalGroup(
         layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addComponent(MainToolbar, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(MainTabbedPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 487, Short.MAX_VALUE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(StatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
      );

      pack();
   }// </editor-fold>//GEN-END:initComponents

	/**
	 * This action shows a file chooser modified to select a folder
	 * for adding all images in folders (and subfolders) to the project
	 * @param evt
	 */
	@Action
	public void addImagesAction() {
		javax.swing.JFileChooser fc = new javax.swing.JFileChooser();
		fc.setMultiSelectionEnabled(true);
		SupportedImagesFileFilter filter = new SupportedImagesFileFilter();
		fc.setFileFilter(filter);
		int result = fc.showOpenDialog(AddImagesButton);
		if (result == javax.swing.JFileChooser.APPROVE_OPTION) {
			File[] files = fc.getSelectedFiles();
			DiskFileLoader loader = new DiskFileLoader(files);
			loader.addToProject(project);
			fireSourceAddedOrRemoved();
		}
	}

	/**
	 * Activate the processing of the project
	 */
	 private void GenerateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_GenerateButtonActionPerformed
		 //First we need at least an image to process...
		 if (project.getSources().size() <= 0) {
			 JOptionPane.showMessageDialog(null, "There is no image to process!");
			 return;
		 }
		 //we now need the ouptput file
		 JFileChooser fc = new javax.swing.JFileChooser();
		 fc.setDialogType(JFileChooser.SAVE_DIALOG);
		 PDFFileFilter filter = new PDFFileFilter();
		 fc.setFileFilter(filter);
		 int result = fc.showSaveDialog(GenerateButton);
		 if (result == javax.swing.JFileChooser.APPROVE_OPTION) {
			 //Now I do get the filename
			 String filename = fc.getSelectedFile().getAbsolutePath();
			 if (filename.toLowerCase().indexOf(".pdf") < filename.length() - 5) { //extension
				 filename += ".pdf";
			 }

			 //if i can save the file we can setup the project
			 if (confirmOverwrite(filename)) {
				 //I can save the file
				 if (storeProjectSettings()) {
					 setWorking(true);
					 try {
						 Integer workers = (Integer) workersSpinner.getValue();
						 engine = new Engine(workers.intValue());
						 engine.addCallBack(this);
						 engine.setProject(project);
						 engine.setOutputStream(new FileOutputStream(new File(filename)));
						 engine.start();
					 } catch (FileNotFoundException ex) {
						 processEnded(false);
					 } catch (Exception ex) {
						 processEnded(false);
					 }
				 }

			 }
		 }
	 }//GEN-LAST:event_GenerateButtonActionPerformed

	 private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutMenuItemActionPerformed
		 AboutBox ab = new AboutBox(this, true);
		 ab.setVisible(true);
	 }//GEN-LAST:event_aboutMenuItemActionPerformed

	 private void SourcesTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_SourcesTableKeyReleased
		 updateSourcePreviewImage();
	 }//GEN-LAST:event_SourcesTableKeyReleased

	 private void SourcesTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_SourcesTableMouseReleased
		 updateSourcePreviewImage();
	 }//GEN-LAST:event_SourcesTableMouseReleased

	 private void PreviewButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_PreviewButtonActionPerformed
		 generateProcessPreviewImage();
	 }//GEN-LAST:event_PreviewButtonActionPerformed

	 private void AddZipPackageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AddZipPackageButtonActionPerformed
	 }//GEN-LAST:event_AddZipPackageButtonActionPerformed

	 private void SelectAllMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SelectAllMenuItemActionPerformed
		 SourcesTable.selectAll();
	 }//GEN-LAST:event_SelectAllMenuItemActionPerformed

	/**
	 * Get a list of all the selected sources into the SourcesTable.
	 * @return a linkedlist of the selected sources reference
	 */
	LinkedList<IImageSource> getSelectedSources() {
		LinkedList<IImageSource> selected = new LinkedList<IImageSource>();
		for (int i : SourcesTable.getSelectedRows()) {
			selected.add(project.getSources().get(i));
		}
		return selected;
	}//LinkedList<IImageSource> getSelectedSources()

	 private void DeleteMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DeleteMenuItemActionPerformed
		 LinkedList<IImageSource> selected = getSelectedSources();
		 for (IImageSource source : selected) {
			 project.getSources().remove(source);
		 }
		 fireSourceAddedOrRemoved();
	 }//GEN-LAST:event_DeleteMenuItemActionPerformed

	void clearSelection() {
		ListSelectionModel model = SourcesTable.getSelectionModel();
		model.clearSelection();

	}

	/**
	 * Set IImageSource selection state
	 * @param source source to change the state
	 * @param isSelected selection state
	 */
	void setSourceSelected(IImageSource source, boolean isSelected) {
		ListSelectionModel model = SourcesTable.getSelectionModel();
		int i = project.getSources().indexOf(source);
		if (isSelected) {
			model.addSelectionInterval(i, i);
		} else {
			model.removeSelectionInterval(i, i);
		}
	}//void setSourceSelected(IImageSource source,boolean isSelected)

	void selectNone() {
		ListSelectionModel model = SourcesTable.getSelectionModel();
		model.clearSelection();
	}//void selectNone()

	void selectByOrientation(Orientation orientation) {
		ListSelectionModel model = SourcesTable.getSelectionModel();
		model.clearSelection();
		for (IImageSource source : project.getSources()) {
			if (source.getInfo().getOrientation().equals(orientation)) {
				setSourceSelected(source, true);
			}
		}
	}

	 private void SelectHorizontalMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SelectHorizontalMenuItemActionPerformed
		 selectByOrientation(Orientation.LANDSCAPE);
	 }//GEN-LAST:event_SelectHorizontalMenuItemActionPerformed

	 private void SelectVerticalMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SelectVerticalMenuItemActionPerformed
		 selectByOrientation(Orientation.PORTRAIT);
	 }//GEN-LAST:event_SelectVerticalMenuItemActionPerformed

	 private void MassSetMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MassSetMenuItemActionPerformed
		 MassSetterDialog dialog = new MassSetterDialog(this, true);
		 dialog.showDialog();
		 if (dialog.isOkPressed()) {
			 boolean split = dialog.isSplit();
			 SourceRotation rotation = dialog.getRotation();
			 LinkedList<IImageSource> selected = getSelectedSources();
			 for (IImageSource source : selected) {
				 source.getTransformations().setSplit(split);
				 source.getTransformations().setRotate(rotation);
			 }
			 updateProjectSourcesTable();
		 }
	 }//GEN-LAST:event_MassSetMenuItemActionPerformed

	 private void addImagesMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addImagesMenuItemActionPerformed
	 }//GEN-LAST:event_addImagesMenuItemActionPerformed

	 private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
		 System.exit(0);
	 }//GEN-LAST:event_exitMenuItemActionPerformed

	 private void helpMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_helpMenuItemActionPerformed
		 HelpFrame.showHelp(null);
	 }//GEN-LAST:event_helpMenuItemActionPerformed

	 private void reportIssueItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reportIssueItemActionPerformed
		 browseUrl("http://code.google.com/p/rilego/issues/list");
	 }//GEN-LAST:event_reportIssueItemActionPerformed

	 private void rilegoWebsiteItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rilegoWebsiteItemActionPerformed
		 browseUrl("http://www.kirys.it/software/rilego.html");
	 }//GEN-LAST:event_rilegoWebsiteItemActionPerformed

	/**
	 * This method store the setting into the interface to the active project
	 * @return true if the settings are valid
	 */
	boolean storeProjectSettings() {
		//Get project settings
		project.setTitle(titleTextField.getText());
		project.setAuthor(authorTextField.getText());
		SplitMode sm = SplitMode.Normal;
		if (splitModeCombo.getSelectedItem() instanceof SplitMode) {
			sm = (SplitMode) splitModeCombo.getSelectedItem();
		}
		PdfBuilder outputBuilder = new PdfBuilder((IMediaType) mediaTypeCombo.getSelectedItem());
		project.setBuilder(outputBuilder);
		IActiveProcessorFactory factory = new BasicFullProcessorFactory();
		IImageSplitter splitter = factory.getTransformer().getSplitter();
		if (splitter instanceof SplitToTwo) {
			((SplitToTwo) splitter).setMangaMode(sm == SplitMode.Manga);
		}
		factory.getFilters().clear();
		for (IFilterSetter setter : manager) {
			if (setter.isSelected()) {
				factory.getFilters().add(setter.getFilter().clone());
			}
		}
		project.setFactory(factory);

		return true;
	}//boolean storeProjectSettings()

	/**
	 * Update the source preview panel
	 */
	private void updateSourcePreviewImage() {
		int r = SourcesTable.getSelectedRow();
		if ((r >= 0) && (r != currentSelection)) {
			currentSelection = r;
			IImageSource source = project.getSources().get(r);
			BufferedImage image;
			try {
				image = AbstractFullProcessor.loadFromStream(source.getStream());
				((SimpleImagePanel) SourcesPreviewPanel).setImage(image);
			} catch (IOException ex) {
				Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}//private void updateSourcePreviewImage()

	private void generateProcessPreviewImage() {
		if (currentSelection >= 0) {
			IImageSource source = project.getSources().get(currentSelection);
			BufferedImage image;
			storeProjectSettings();
			Engine appoengine = new Engine();
			appoengine.setProject(project);
			appoengine.addCallBack(this);
			AbstractFullProcessor p = (AbstractFullProcessor) appoengine.createProcessor(source);

			try {
				((SimpleImagePanel) FilterPreviewPanel).setImage(p.preview());
			} catch (IOException ex) {
				Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

	/**
	 * set/unset the interface in working mode
	 * @param working true if the software is in working mode
	 */
	void setWorking(boolean working) {
		//TODO: stub method
		if (working) {
			monitor.start();
		} else {
			monitor.stop();
			progressBar.setVisible(false);
			iconContainer.setIcon(idleIcon);
		}
	}//void setWorking (boolean working)

	/**
	 * This method check if the file exists if it does ask the user for confirmation.
	 * @param filename filename to check
	 * @return true if file doesn't exists or if the user confirmed overwrite
	 */
	private boolean confirmOverwrite(String filename) {
		if ((new File(filename)).exists()) {
			int response = JOptionPane.showConfirmDialog(null,
					  "File '" + filename + "' exists! \nOverwrite existing file?", "Confirm Overwrite",
					  JOptionPane.OK_CANCEL_OPTION,
					  JOptionPane.QUESTION_MESSAGE);
			if (response == JOptionPane.CANCEL_OPTION) {
				return false;
			}
		}
		return true;
	}//private boolean confirmOverwrite(String filename)

	/**
	 * this have to be called when a command alters the number of sources of a project
	 */
	public void fireSourceAddedOrRemoved() {
		project.sortSources();
		selectNone();
		updateProjectSourcesTable();
	}//public void fireSourceAddedOrRemoved()

	/**
	 * Update the sources List
	 */
	public void updateProjectSourcesTable() {
		TableModel tm = SourcesTable.getModel();
		if (tm instanceof SourcesTableModel) {
			((SourcesTableModel) tm).fireTableDataChanged();
		}
	}//public void updateProjectSources()

	private void newProject() {
		project = new Project();
		manager = new FiltersManager();
		FiltersTreeModel f = new FiltersTreeModel(manager);
		FiltersPropertiesTree.setModel(f);
		SourcesTableModel tm = new SourcesTableModel(project);
		tm.assignToTable(SourcesTable);
	}//private void newProject()

	public static void showGui() {
		java.awt.EventQueue.invokeLater(new Runnable() {

			@Override
			public void run() {
				new MainFrame().setVisible(true);
			}
		});
	}//public static void showGui()
   // Variables declaration - do not modify//GEN-BEGIN:variables
   private javax.swing.JPopupMenu.Separator ActionSeparator;
   private javax.swing.JButton AddDirectoryButton;
   private javax.swing.JButton AddImagesButton;
   private javax.swing.JButton AddZipPackageButton;
   private javax.swing.JMenuItem DeleteMenuItem;
   private javax.swing.JLabel DirectionLabel;
   private javax.swing.JPanel FilterPreviewPanel;
   private javax.swing.JPanel FiltersPanel;
   private javax.swing.JTree FiltersPropertiesTree;
   private javax.swing.JScrollPane FiltersPropertiesTreeScroller;
   private javax.swing.JButton GenerateButton;
   private javax.swing.JMenu HelpMenu;
   private javax.swing.JComboBox ImageCompressionCombo;
   private javax.swing.JSplitPane ImagesProcessingOptionsPanel;
   private javax.swing.JPanel ImagesProcessingPanel;
   private javax.swing.JTextArea InfoLogArea;
   private javax.swing.JScrollPane InfoLogScroll;
   private javax.swing.JMenuItem InvertSelectionMenuItem;
   private javax.swing.JMenuBar MainMenu;
   private javax.swing.JTabbedPane MainTabbedPanel;
   private javax.swing.JToolBar MainToolbar;
   private javax.swing.JMenuItem MassSetMenuItem;
   private javax.swing.JMenu MultipleSelectionMenu;
   private javax.swing.JComboBox OutputDirectionCombo;
   private javax.swing.JButton PreviewButton;
   private javax.swing.JScrollPane PreviewPanelScroller;
   private javax.swing.JMenuItem SelectAllMenuItem;
   private javax.swing.JMenuItem SelectHorizontalMenuItem;
   private javax.swing.JMenuItem SelectVerticalMenuItem;
   private javax.swing.JSplitPane SourcesPanel;
   private javax.swing.JPopupMenu SourcesPopupMenu;
   private javax.swing.JPanel SourcesPreviewPanel;
   private javax.swing.JScrollPane SourcesScrollPanel;
   private javax.swing.JTable SourcesTable;
   private javax.swing.JPanel SplitModePanel;
   private javax.swing.JPanel StatusPanel;
   private javax.swing.JPopupMenu.Separator TransformationSeparator;
   private javax.swing.JMenuItem aboutMenuItem;
   private javax.swing.JMenuItem addDirectoryMenuItem;
   private javax.swing.JMenuItem addImagesMenuItem;
   private javax.swing.JLabel authorLabel;
   private javax.swing.JTextField authorTextField;
   private javax.swing.JMenuItem exitMenuItem;
   private javax.swing.JMenuItem helpMenuItem;
   private javax.swing.JPopupMenu.Separator helpSeparator;
   private javax.swing.JLabel iconContainer;
   private javax.swing.JLabel imageCompressionTypeLabel;
   private javax.swing.JPopupMenu.Separator issueSeparator;
   private javax.swing.JMenuItem jMenuItem3;
   private javax.swing.JMenuItem jMenuItem4;
   private javax.swing.JPanel jPanel1;
   private javax.swing.JToolBar.Separator jSeparator1;
   private javax.swing.JPopupMenu.Separator jSeparator2;
   private javax.swing.JPopupMenu.Separator jSeparator3;
   private javax.swing.JComboBox mediaTypeCombo;
   private javax.swing.JLabel mediaTypeLabel;
   private javax.swing.JPanel outputPanel;
   private javax.swing.JProgressBar progressBar;
   private javax.swing.JMenu projectMenu;
   private javax.swing.JMenuItem reportIssueItem;
   private javax.swing.JMenuItem rilegoWebsiteItem;
   private javax.swing.JComboBox splitModeCombo;
   private javax.swing.JLabel statusLabel;
   private javax.swing.JLabel titleLabel;
   private javax.swing.JTextField titleTextField;
   private javax.swing.JLabel workersNumberLabel;
   private javax.swing.JSpinner workersSpinner;
   // End of variables declaration//GEN-END:variables

	@Override
	public void sendInfo(String message, EngineStatusInfo info) {
		statusLabel.setText(message);
		if (info != null) {
			if (info.isRunning()) {
				progressBar.setVisible(true);
				progressBar.setValue(info.getCompletition());
			} else {
				progressBar.setVisible(false);
			}
		}

	}//public void sendInfo(String message, EngineStatusInfo info)

	@Override
	public void processEnded(boolean successfull) {
		setWorking(false);
		engine = null;
	}//public void processEnded()

	@Override
	public void logMessage(String message) {
		addLogLine(message);
	}//public void logMessage(String message)

	public void addLogLine(String line) {
		if (line != null) {
			InfoLogArea.setText(InfoLogArea.getText() + line + "\n");
		}
		InfoLogArea.setCaretPosition(InfoLogArea.getText().length());
		this.repaint();
	}//public void addLogLine(String line)

	@Action
	public void addDirectoryAction() {
		final JCheckBox recursive = new JCheckBox();
		recursive.setText("Recursive");
		recursive.setSelected(false);

		javax.swing.JFileChooser fc = new javax.swing.JFileChooser() {

			@Override
			protected JDialog createDialog(Component parent) throws HeadlessException {
				JDialog dialog = super.createDialog(parent);
				dialog.add(recursive, BorderLayout.SOUTH);
				dialog.pack();
				return dialog;
			}
		};
		fc.setDialogTitle("Choose a directory");
		if (fc.getLayout() instanceof java.awt.BorderLayout) {
			JPanel p = new JPanel(new BorderLayout());
		}
		fc.add(recursive, java.awt.BorderLayout.SOUTH);
		fc.updateUI();
		fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		int result = fc.showOpenDialog(AddDirectoryButton);
		if (result == javax.swing.JFileChooser.APPROVE_OPTION) {
			int i = 0;
			File f = fc.getSelectedFile();
			DiskFileLoader loader = new DiskFileLoader(f, recursive.isSelected() ? 3 : 0);
			loader.addToProject(project);
			fireSourceAddedOrRemoved();
		}
	}

	@Action
	public void addZipPackageAction() {
		javax.swing.JFileChooser fc = new javax.swing.JFileChooser();
		fc.setMultiSelectionEnabled(true);
		SupportedPackagesFileFilter filter = new SupportedPackagesFileFilter();
		fc.setFileFilter(filter);
		int result = fc.showOpenDialog(AddZipPackageButton);
		if (result == javax.swing.JFileChooser.APPROVE_OPTION) {
			File[] files = fc.getSelectedFiles();
			for (File f : files) {
				try {
					ZipPackageLoader loader = new ZipPackageLoader(f);
					loader.addToProject(project);
				} catch (IOException ex) {
					Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
				}
			}
			fireSourceAddedOrRemoved();
		}
	}

	@Action
	public void clearProject() {
		project.getSources().clear();
		fireSourceAddedOrRemoved();

	}
}
